package io.gitee.hefren.hhconfig.client.conf;

import com.google.common.base.Throwables;
import io.gitee.hefren.hhconfig.client.beans.SpringValue;
import io.gitee.hefren.hhconfig.client.utils.PlaceholderHelper;
import io.gitee.hefren.utils.FieldUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * 对 @Value 注解的字段进行动态刷新
 * @Date 2024/6/4
 * @Author lifei
 */
public class SpringValueProcessor implements BeanPostProcessor, BeanFactoryAware, ApplicationListener<EnvironmentChangeEvent> {

    private BeanFactory beanFactory;
    private static final PlaceholderHelper placeholderHelper = PlaceholderHelper.instance();
    private static final MultiValueMap<String, SpringValue> PLACEHOLDER_KEYS = new LinkedMultiValueMap<>();

    /**
     * 获取@Value 中 配置key 对应的 bean
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 扫描 @Value
        List<Field> annotationFields = FieldUtils.findAnnotationFields(bean.getClass(), Value.class);
        for (Field annotationField : annotationFields) {
            Value value = annotationField.getAnnotation(Value.class);
            String placeholder = value.value();
            // ${k.v} ==> k.v
            Set<String> keys = placeholderHelper.extractPlaceholderKeys(placeholder);
            for (String key : keys) {
                PLACEHOLDER_KEYS.add(key, new SpringValue(bean, beanName, key, placeholder, annotationField));
            }
        }
        return bean;
    }

    /**
     * 实现动态刷新 @Value 注解的配置
     * @param event
     */
    @Override
    public void onApplicationEvent(EnvironmentChangeEvent event) {
        Set<String> keys = event.getKeys();
        if (Objects.isNull(keys) || keys.isEmpty()) {
            return;
        }
        try {
            for (String key : keys) {
                List<SpringValue> springValues = PLACEHOLDER_KEYS.get(key);
                if (Objects.isNull(springValues) || springValues.isEmpty()) {
                    continue;
                }
                for (SpringValue springValue : springValues) {
                    Object fieldValue = placeholderHelper.getSpringFiledValue((ConfigurableBeanFactory) beanFactory, springValue.getBeanName(), springValue.getPlaceholder());
                    Field field = springValue.getField();
                    field.setAccessible(true);
                    field.set(springValue.getBean(), fieldValue);
                }
            }
        }catch (Exception e) {
            System.err.println(Throwables.getStackTraceAsString(e));
        }
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
}
